{***************************************************************
    SpyGestion  Copyright (C) 2008 Christophe KOALI <nature2gas@gmail.com>
    
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    
****************************************************************}
unit modCoreRecu;

interface

uses modBaseType, Classes, SysUtils, ESBDates, modCore, modClassRessources, modBaseRessources;

const
   MAX_RES_OG = 16;

type
   TResultatBestProd = array[0..MAX_RES_OG] of integer;


procedure RecuCalcul(Profondeur: integer);

// Les données de ressources sont à 100%
function GetBestActivityProduct(CostBuild: TOGRessourceAll; CurrProduct: TList; var xTempProduct: integer): TResultatBestProd;


procedure DupliqueTList(Src, Destination: TList);

implementation



var
    bgBestConfigProd: TResultatBestProd;
    bgCurrConfig: TResultatBestProd ;

    // Evite de les passer en paramètre à chaque appel récursif
    gbCostBuild   : TOGRessourceAll;
    gbSourceProduc: TList;
    gbMinTemp     : integer;
    gbTempList    : TList;
    gbMaxIndex    : integer;




procedure SetFactorFromCurrent(CurrProduct: TList);
var i: integer;
    cE: POGResUsed;
begin

    // On sous entend que CurrProduct.Count > 0

    for i := 0 to CurrProduct.Count - 1 do begin
        cE := CurrProduct.Items[i];
        cE.Activite := bgCurrConfig[i];
    end;
end;


procedure DupliqueTList(Src, Destination: TList);
var i :integer;
    x, y: POGResUsed;
begin

    Destination.Clear;

    if Src.Count = 0 then exit;

    for i := 0 to Src.Count - 1 do begin
       New(x);
       y := Src.Items[i];

       x.IdOpt := y.IdOpt;
       x.prMetal := y.prMetal;
       x.prCristal  := y.prCristal;
       x.prDeuterium  := y.prDeuterium;
       x.prEnergie  := y.prEnergie;
       x.csEnergieUsed  := y.csEnergieUsed;
       x.csEnergieAllow  := y.csEnergieAllow;
       x.Activite        := y.Activite;

       x.ActiviteForOptimization := y.ActiviteForOptimization;

       x.Element := y.Element;
       x.ElementGID := y.ElementGID;
       x.ElementLVL := y.ElementLVL;

       Destination.Add(x);

    end;

end;


function GetBestActivityProduct(CostBuild: TOGRessourceAll; CurrProduct: TList; var xTempProduct: integer): TResultatBestProd;
var i: integer;
    cE: POGResUsed;
begin

     // A l'origine, les données sont à 100%

    gbSourceProduc := CurrProduct;
    gbCostBuild    := CostBuild;

    // Initialisation des facteurs
    for i := 0 to CurrProduct.Count - 1 do begin
       cE := CurrProduct.Items[i];


       if cE.prEnergie > 0 then begin
          // Centrale...
          // Vérifie si elle consomme des ressources
          if (cE.prMetal = 0) and
              (cE.prCristal = 0) and
              (cE.prDeuterium = 0) then begin

              // Ne fait que produire, on laisse à 100%
              cE.Activite := -1;
          end;

       end else if (cE.prMetal = 0) and (cE.prCristal = 0) and (cE.prDeuterium = 0) then begin
          // impossible à prédire la production, cela est du au fait que l'activite
          // doit être nulle...
          // ou alors à une erreur de parsing
          cE.Activite := -1;
       end;

       bgBestConfigProd[i] := cE.Activite;
       bgCurrConfig[i]     := bgBestConfigProd[i];
    end;


    gbTempList := TList.Create;

    

    DupliqueTList(CurrProduct, gbTempList);

    // + l'infini au début
    gbMinTemp := 1412009888;

    gbMaxIndex := gbSourceProduc.Count - 1;
    // Ok, maintenant on vérifie si ce dernier index n'est pas en -1
    repeat
       cE := CurrProduct.Items[gbMaxIndex];

       if cE.Activite = -1 then
          Dec(gbMaxIndex)
       else
          break;

    until gbMaxIndex <= 0;


    if gbMaxIndex > 0 then begin
       RecuCalcul(0);
    end;


    FreeTList(gbTempList);
    gbTempList.Free;
    gbTempList := nil;

    Result := bgBestConfigProd;
    xTempProduct := gbMinTemp;


end;

procedure RecuCalcul(Profondeur: integer);
var CurrElement: POGResUsed;
    i, j, IdRes, TempProduct : integer;

    ProducParHeure : TOGRessourceAll;

begin

     if Profondeur >= gbSourceProduc.Count then begin
        exit;
     end;


     if gbMaxIndex = Profondeur then begin

        for i := 10 downto 0 do begin

             if bgCurrConfig[Profondeur] < 0 then break;

             // Met à jour la liste
             UpdateTList(gbSourceProduc, gbTempList);

             // Définit les facteurs de production
             SetFactorFromCurrent(gbTempList);

             // Met à jour les valeurs de production en fonction des facteurs
             UpdateWithTheActivityPropertie(gbTempList);

             // Adapte le facteur global de production en fonction de l'énergie disponible
             GetRessourceWithFactorProduct(gbTempList);

             // Calcule la production par heure
             ProducParHeure := mcrGetCalculTotalParHeure(gbTempList);

             // Obtient le temps de production
             TempProduct := GetTimeNeedToProductThisRes(gbCostBuild, ProducParHeure, IdRes);

             if (TempProduct < gbMinTemp) and (TempProduct > 0) then begin
                 gbMinTemp := TempProduct;

                 bgBestConfigProd := bgCurrConfig;
             end;

             bgCurrConfig[Profondeur] := bgCurrConfig[Profondeur] - 10;


        end;

        exit;
     end;

     CurrElement := gbSourceProduc.Items[Profondeur];
     if CurrElement.Activite <= 0 then begin
        RecuCalcul(Profondeur + 1);
        exit;
     end;


     for i := 10 downto 0 do begin

          // Remet les autres à 100%
          for j := Profondeur + 1 to gbSourceProduc.Count - 1 do begin
             if bgCurrConfig[j] <> -1 then begin
                bgCurrConfig[j] := 100;

                // Sinon laisse à -1
             end;

          end;

          RecuCalcul(Profondeur + 1);
          bgCurrConfig[Profondeur] := bgCurrConfig[Profondeur] - 10;
          if bgCurrConfig[Profondeur] < 0 then break;

     end;

end;


end.
